package com.scpii.api.common.exception;

import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class ClientException extends RuntimeException {

	/**
	 * 
	 */
	private static final long serialVersionUID = -3817573290201955838L;

	public static final String ERROR = "error";
	public static final String DESCRIPTION = "error_description";
	public static final String URI = "error_uri";
	public static final String INVALID_REQUEST = "invalid_request";
	public static final String INVALID_CLIENT = "invalid_client";
	public static final String UNAUTHORIZED_CLIENT = "unauthorized_client";
	public static final String INVALID_TOKEN = "invalid_token";
	public static final String INVALID_GRANT = "invalid_grant";
	public static final String UNSUPPORTED_GRANT_TYPE = "unsupported_grant_type";
	public static final String ACCESS_DENIED = "access_denied";

	private Map<String, String> additionalInformation = null;

	public ClientException(String msg, Throwable t) {
		super(msg, t);
	}

	public ClientException(String msg) {
		super(msg);
	}

	public String getError() {
		return "invalid_request";
	}

	public int getErrorCode() {
		return 1005;
	}

	public Map<String, String> getAdditionalInformation() {
		return this.additionalInformation;
	}

	public void addAdditionalInformation(String key, String value) {
		if (this.additionalInformation == null) {
			this.additionalInformation = new TreeMap<String, String>();
		}

		this.additionalInformation.put(key, value);

	}

	public static ClientException create(String errorCode, String errorMessage) {

		if (INVALID_CLIENT.equals(errorCode)) {
			return new InvalidClientException(errorMessage);
		} else if (INVALID_GRANT.equals(errorCode)) {
			return new InvalidUserException(errorMessage);
		} else if (INVALID_TOKEN.equals(errorCode)) {
			return new InvalidTokenException(errorMessage);
		} else if (INVALID_REQUEST.equals(errorCode)) {
			return new InvalidRequestException(errorMessage);
		} else if (UNSUPPORTED_GRANT_TYPE.equals(errorCode)) {
			return new UnSupportedGrantTypeException(errorMessage);
		} else if (ACCESS_DENIED.equals(errorCode)) {
			return new UserDeniedAuthorizationException(errorMessage);
		} else {
			return new ClientException(errorMessage);
		}
	}

	public static ClientException valueOf(Map<String, String> errorParams) {
		String errorCode = errorParams.get(ERROR);
		String errorMessage = errorParams.containsKey(DESCRIPTION) ? errorParams
				.get(DESCRIPTION) : null;
		ClientException ex = create(errorCode, errorMessage);
		Set<Map.Entry<String, String>> entries = errorParams.entrySet();
		for (Map.Entry<String, String> entry : entries) {
			String key = entry.getKey();
			if (!ERROR.equals(key) && !DESCRIPTION.equals(key)) {
				ex.addAdditionalInformation(key, entry.getValue());
			}
		}

		return ex;
	}

	@Override
	public String toString() {
		return getSummary();
	}

	public String getSummary() {

		StringBuilder builder = new StringBuilder();

		String delim = "";

		String error = this.getError();
		if (error != null) {
			builder.append(delim).append("error=\"").append(error).append("\"");
			delim = ", ";
		}

		String errorMessage = this.getMessage();
		if (errorMessage != null) {
			builder.append(delim).append("errorDescription=\"")
					.append(errorMessage).append("\"");
			delim = ", ";
		}

		Map<String, String> additionalParams = this.getAdditionalInformation();
		if (additionalParams != null) {
			for (Map.Entry<String, String> param : additionalParams.entrySet()) {
				builder.append(delim).append(param.getKey()).append("=\"")
						.append(param.getValue()).append("\"");
				delim = ", ";
			}
		}

		return builder.toString();

	}
}
